<template>
  <div class="notice-container" :class="mode">
    <div ref="contentRef" class="notice-content">
      <p>{{ msg }}</p>
    </div>
  </div>
</template>

<script lang="ts" setup name="NoticeBar">
  import { nextTick, onMounted, onUnmounted, ref } from 'vue';

  const props = defineProps({
    msg: {
      type: String,
      required: true
    },
    mode: {
      type: String,
      default: 'vertical' // 'vertical'|'horizontal'
    }
  });

  const timer = ref();

  const contentRef = ref();

  const bindVerticalAni = () => {
    const contentEl = contentRef.value;
    if (!contentEl) return;
    const { width: pw } = contentEl.parentNode.getBoundingClientRect();
    const { width: cw } = contentEl.getBoundingClientRect();
    if (cw > pw) {
      const cloneP = document.createElement('p');
      cloneP.innerHTML = contentEl.children[0].innerHTML;
      contentEl.appendChild(cloneP);
      let x = 0;
      const moveAni = () => {
        if (x > cw) {
          x = x - cw;
        } else {
          x += 0.5;
        }
        contentEl.style.marginLeft = `${-x}px`;
        timer.value = requestAnimationFrame(moveAni);
      };

      moveAni();
    }
  };

  const bindHorizontalAni = () => {
    const contentEl = contentRef.value;
    if (!contentEl) return;
    const { height: ph } = contentEl.parentNode.getBoundingClientRect();
    const { height: ch } = contentEl.getBoundingClientRect();
    if (ch > ph) {
      const cloneP = document.createElement('p');
      cloneP.innerHTML = contentEl.children[0].innerHTML;
      contentEl.appendChild(cloneP);
      let y = 0;
      const moveAni = () => {
        if (y > ch) {
          y = y - ch;
        } else {
          y += 0.5;
        }
        contentEl.style.marginTop = `${-y}px`;
        timer.value = requestAnimationFrame(moveAni);
      };

      moveAni();
    }
  };

  const bindAni = () => {
    if (timer.value) cancelAnimationFrame(timer.value);
    nextTick(props.mode === 'vertical' ? bindVerticalAni : bindHorizontalAni);
  };

  onMounted(() => {
    setTimeout(bindAni, 1000);
    window.addEventListener('resize', bindAni);
  });

  onUnmounted(() => {
    if (timer.value) cancelAnimationFrame(timer.value);
    window.removeEventListener('resize', bindAni);
  });
</script>

<style lang="less">
  .notice-container {
    padding: 8px 15px;
    overflow: hidden;
    &.vertical > .notice-content {
      width: max-content;
      display: flex;
      flex-direction: row;
      align-items: center;
      p {
        white-space: nowrap;
        word-break: break-all;
      }
    }

    &.horizontal > .notice-content {
      height: auto;
      p {
        margin-bottom: 15px;
        word-break: break-all;
      }
    }
  }
</style>
